#include "AuctionManager.h"
#include "PeopleManager.h"
#include "TeamManager.h"
#include "User.h"
#include "ZStream.h"
#include "ServiceProvider.h"
#include "People.h"
#include "PeopleFunctors.h"

#include <cassert>
#include <algorithm> // random_shuffle only

AuctionManager::AuctionManager(ServiceProvider* i_sp) : m_sp(i_sp)
{
	assert(m_sp);
}

bool AuctionManager::AddBet(const Bet& i_bet)
{
	// if the bet is acceptable, keep it alive.
	// then the Player will choose which one to sign
	//if(i_bet.m_player->IsBetAcceptable())...

	BetVecIt it = STL::find_if(m_bets.begin(), m_bets.end(), [&](const Bet& i_currentBet) -> bool {return i_currentBet.m_player == i_bet.m_player;});

	if(it == m_bets.end())
	{
#ifndef DARIO
		if(i_bet.m_salary < i_bet.m_player->CalculateExpectedSalary() || static_cast<int>(i_bet.m_salary) > i_bet.m_team->GetBudget())
#else
		const int bid = static_cast<int>(i_bet.m_bid);
		if(	(bid < i_bet.m_player->BuyValue()) || 
			(((bid > i_bet.m_team->GetBudget()) && (i_bet.m_team->GetNumPlayers() > Team::GetParams().MIN_TEAM_PLAYERS ))))
#endif
		{
			return false;
		}

		m_bets.push_back(i_bet);
		return true;
	}

	Bet& old_bet = (*it);

#ifndef DARIO
	if(i_bet.m_salary > old_bet.m_salary && i_bet.m_years <= 5)
	{
		old_bet.m_salary = i_bet.m_salary;
		old_bet.m_team = i_bet.m_team;
		i_bet.m_player->SetContract(i_bet.m_salary, i_bet.m_years);
		return true;
	}
#else
	if(i_bet.m_bid > old_bet.m_bid)
	{
		old_bet.m_bid = i_bet.m_bid;
		old_bet.m_team = i_bet.m_team;
		return true;
	}
#endif

	return false;
}

void AuctionManager::Clear()
{
	m_bets.clear();
}

void AuctionManager::Dispatch(const bool i_doNotPrompt)
{
	if(m_bets.empty())
		return;

	if(!i_doNotPrompt)
	{
		STD::cout << "\n EVENTI MERCATO:\n";
	}

	for(BetVecIt it = m_bets.begin(); it != m_bets.end(); ++it)
	{
		Bet& bet = (*it);

		if(!bet.m_player->IsBusy())
		{
#ifndef DARIO
			bet.m_team->BuyPlayer(bet.m_player, bet.m_salary, bet.m_years);
#else
			bet.m_team->BuyPlayer(bet.m_player, bet.m_bid, 0);
#endif 
			if(!i_doNotPrompt)
			{
#ifndef DARIO
				STD::cout << " ! " << bet.m_team->GetName() << " ha comprato " << bet.m_player->GetName() << " con un contratto di " << bet.m_player->GetContract()->m_years << " anni e " << bet.m_player->GetContract()->m_salary << " Banane a partita!.\n";
#else
				STD::cout << " ! " << bet.m_team->GetName() << " ha comprato " << bet.m_player->GetName() << " per " << bet.m_bid << " Banane!.\n";
#endif 
			}
		}
	}

	if(!i_doNotPrompt)
	{
		STD::cout << "\n";
	}

	m_bets.clear();
}

ZStream& AuctionManager::Serialize(ZStream& o_stream) const
{
	o_stream.WriteOpenTag("Auctions");

	o_stream.WriteAttribute("BetNums", m_bets.size());

	for(size_t i = 0; i < m_bets.size(); ++i)
	{
		o_stream.WriteOpenTag("Entry");
		o_stream.WriteAttribute("PlayerID", m_bets[i].m_player->GetId());
		o_stream.WriteAttribute("TeamID", m_bets[i].m_team->GetID());
#ifndef DARIO
		o_stream.WriteAttribute("Salary", m_bets[i].m_salary);
		o_stream.WriteAttribute("Years", m_bets[i].m_years);
#else
		o_stream.WriteAttribute("Bid", m_bets[i].m_bid);
#endif
		o_stream.WriteCloseTag("Entry");
	}

	o_stream.WriteCloseTag("Auctions");

	return o_stream;
}

ZStream& AuctionManager::Deserialize(ZStream& i_stream)
{
	m_bets.clear();

	i_stream.SkipLine();

	size_t betsNum;
	i_stream.ReadAttribute(betsNum);

	for(size_t i = 0; i < betsNum; ++i)
	{
		Bet bet;
		size_t playerID, teamID;

		i_stream.SkipLine();
		i_stream.ReadAttribute(playerID);
		i_stream.ReadAttribute(teamID);

		bet.m_player = m_sp->GetPeopleMgr().GetPeopleFromID(playerID);
		bet.m_team = m_sp->GetTeamMgr().GetTeam(teamID);

#ifndef DARIO
		i_stream.ReadAttribute(bet.m_salary);
#else
		i_stream.ReadAttribute(bet.m_bid);
#endif
		i_stream.SkipLine();
	}

	i_stream.SkipLine();

	return i_stream;
}